﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace FormDesigner
{
    public partial class Table : UserControl
    {
        /// <summary>
        /// 选中表格子控件事件
        /// </summary>
        public event EventHandler CtrlSelectedEvent;
        /// <summary>
        /// 选择表格的行线或列线时，允许的误差范围
        /// </summary>
        private static readonly int SELECT_SPACE = 2;
        /// <summary>
        /// 对Table控件的引用，方便其它类直接操作Table
        /// </summary>
        public static Table GlobalTable = null;
        //数据模型
        private DataTable _dataModel;
        //表格和控件顶边的间隔距离
        private int PaddingTop = 5;
        //表格和控件左边的间隔距离
        private int PaddingLeft = 5;

        //表格控件初始的高度和宽度
        private int TableDefaultWidth = 0;
        private int TableDefaultHeight = 0;

        /// <summary>
        /// 表格变动记录
        /// </summary>
        private Stack<DataTable> ModelRecord = new Stack<DataTable>();

        public Table()
        {
            InitializeComponent();
            Table.GlobalTable = this;
            this.MouseMove += Table_MouseMove;
            this.MouseLeftButtonDown += Table_MouseLeftButtonDown;
            this.MouseLeftButtonUp += Table_MouseLeftButtonUp;
        }


        public DataTable Model
        {
            get { return _dataModel; }
            set { _dataModel = value; }
        }

        /// <summary>
        /// 表格宽度
        /// </summary>
        public int TableWidth
        {
            get
            {
                return Model.ListCellWidth.Sum();
            }
        }
        /// <summary>
        /// 表格高度
        /// </summary>
        public int TableHeight
        {
            get
            {
                return Model.ListCellHeight.Sum();
            }
        }

        #region 刷新表格数据模型
        /// <summary>
        /// 重新计算单元格的位置，高度及宽度等信息
        /// </summary>
        /// <param name="isRecord">是否保存改变状态，以便撤销</param>
        public void RefreshModel(bool isRecord = true)
        {
            if (isRecord)
            {
                int hcount = _dataModel.Rows.Count;
                int wcount = _dataModel.Columns.Count;

                while (wcount > Model.ListCellWidth.Count)
                    Model.ListCellWidth.Add(Cell.CellWidth);
                while (hcount > Model.ListCellHeight.Count)
                    Model.ListCellHeight.Add(Cell.CellHeight);

                ModelRecord.Push(Model.DeepCopy());
            }

            for (int i = 0; i < _dataModel.Rows.Count; i++)
            {
                for (int j = 0; j < _dataModel.Columns.Count; j++)
                {
                    Cell c = _dataModel.Rows[i][j];

                    //int xstart = j * Cell.CellWidth;
                    //int ystart = i * Cell.CellHeight;

                    if (c.RowSpan == 0)
                        c.Height = Model.ListCellHeight[i];
                    else
                        c.Height = Model.ListCellHeight.Where((p, index) => index >= c.RowIndex && index <= c.RowIndex + c.RowSpan).Sum();

                    if (c.ColumnSpan == 0)
                        c.Width = Model.ListCellWidth[j];
                    else
                        c.Width = Model.ListCellWidth.Where((p, index) => index >= c.ColumnIndex && index <= c.ColumnIndex + c.ColumnSpan).Sum();

                    int xstart = Model.ListCellWidth.Where((p, index) => index < j).Sum(p => p);
                    int ystart = Model.ListCellHeight.Where((p, index) => index < i).Sum(p => p);

                    c.RowIndex = i;
                    c.ColumnIndex = j;

                    xstart += PaddingLeft;
                    ystart += PaddingTop;

                    c.X = xstart;
                    c.Y = ystart;
                }
            }



            //设置table界面高度和宽度
            var width = TableWidth + 2 * PaddingLeft;
            var height = TableHeight + 2 * PaddingTop;

            Canvas sv = (Canvas)this.Parent;
            if (width > TableDefaultWidth)
                this.Width = sv.Width = width;
            else
                this.Width = sv.Width = TableDefaultWidth;

            if (height > TableDefaultHeight)
                this.Height = sv.Height = height;
            else
                this.Height = sv.Height = TableDefaultHeight;

        }
        #endregion

        #region 初始化表格、添加行、添加列
        /// <summary>
        /// 初始化表格
        /// </summary>
        /// <param name="row"></param>
        /// <param name="column"></param>
        public void InitTable(int row = 3, int column = 3)
        {
            TableDefaultWidth = (int)this.Width;
            TableDefaultHeight = (int)this.Height;

            DataTable dtModel = new DataTable();

            for (int i = 0; i < row; i++)
            {
                List<Cell> _row = new List<Cell>();
                for (int j = 0; j < column; j++)
                    _row.Add(new Cell());
                dtModel.Rows.Add(_row);
            }
            _dataModel = dtModel;
        }

        /// <summary>
        /// 添加行
        /// </summary>
        public void AddRow()
        {
            if (Model == null)
                InitTable();

            List<Cell> row = new List<Cell>();
            for (int i = 0; i < Model.Columns.Count; i++)
                row.Add(new Cell());

            Model.Rows.Add(row);
            RefreshModel();
            this.Refresh();
        }

        /// <summary>
        /// 添加列
        /// </summary>
        public void AddColumn()
        {
            if (Model == null)
                InitTable();

            int columnindex = Model.Columns.Count;
            for (int i = 0; i < Model.Rows.Count; i++)
                Model.Rows[i].Add(new Cell());

            this.RefreshModel();
            this.Refresh();
        }
        #endregion

        #region 合并单元格
        public void MergeCell()
        {
            DataTable dtModel = this.Model;

            Cell sCell = null;
            Cell eCell = null;
            //找到第一个选中的格子
            for (int i = 0; i < dtModel.Rows.Count; i++)
            {
                for (int j = 0; j < dtModel.Columns.Count; j++)
                {
                    Cell c = dtModel.Rows[i][j];
                    if (c.isSelected)
                    {
                        sCell = c;
                        break;
                    }
                }
                if (sCell != null)
                    break;
            }
            //找到最后一个选中的格子
            for (int i = dtModel.Rows.Count - 1; i >= 0; i--)
            {
                for (int j = dtModel.Columns.Count - 1; j >= 0; j--)
                {
                    Cell c = dtModel.Rows[i][j] as Cell;
                    if (c.isSelected)
                    {
                        eCell = c;
                        break;
                    }
                }
                if (eCell != null)
                    break;
            }

            if (sCell == null || eCell == null)
                return;

            int rowspan = eCell.RowIndex - sCell.RowIndex;
            int columnspan = eCell.ColumnIndex - sCell.ColumnIndex;

            sCell.RowSpan = rowspan;
            sCell.ColumnSpan = columnspan;

            for (int i = sCell.RowIndex + 1; i <= eCell.RowIndex; i++)
            {
                Cell c = dtModel.Rows[i][sCell.ColumnIndex] as Cell;
                if (c.isShow)
                    sCell.Height = sCell.Height + c.Height;
            }

            for (int i = sCell.ColumnIndex + 1; i <= eCell.ColumnIndex; i++)
            {
                Cell c = dtModel.Rows[sCell.RowIndex][i] as Cell;
                if (c.isShow)
                    sCell.Width = sCell.Width + c.Width;
            }

            for (int i = 0; i < dtModel.Rows.Count; i++)
            {
                for (int j = 0; j < dtModel.Columns.Count; j++)
                {
                    Cell c = dtModel.Rows[i][j] as Cell;
                    if (c.isSelected && c.isShow)
                    {
                        if (c != sCell)
                        {
                            c.isSelected = false;
                            c.isShow = false;
                        }
                    }
                }
            }

            SetControlInCell();

            this.RefreshModel();
            this.Refresh();

        }
        #endregion

        #region 表格重画事件

        /// <summary>
        /// 表格重画事件
        /// </summary>
        /// <param name="isRePaintCell">是否重画表格单元格</param>
        public void Refresh(bool isRePaintCell = true)
        {
            foreach (var ctrl in this.panel.Children.ToList())
            {
                if (!(ctrl is Label) && !(ctrl is RadioButton) && !(ctrl is CheckBox))
                {
                    if (ctrl is System.Windows.Shapes.Rectangle)
                        if (((System.Windows.Shapes.Rectangle)ctrl).Tag != null && !isRePaintCell)
                            continue;

                    this.panel.Children.Remove(ctrl);
                }
            }
            Table_Paint(isRePaintCell);
        }

        /// <summary>
        /// 重画事件
        /// </summary>
        /// <param name="isRePaintCell">是否重画表格单元格</param>
        public void Table_Paint(bool isRePaintCell = true)
        {
            if (Model == null)
                return;

            #region 画表格
            if (isRePaintCell)
            {
                Model.AllCell.ForEach(c =>
                {
                    if (c.isShow)
                    {
                        System.Windows.Shapes.Rectangle r = new System.Windows.Shapes.Rectangle();
                        r.Tag = c;
                        r.Width = c.Width > 0 ? c.Width - 1 : 0;
                        r.Height = c.Height > 0 ? c.Height - 1 : 0;
                        r.Stroke = new SolidColorBrush(Color.FromArgb(255, 255, 255, 255));
                        r.StrokeThickness = 0.1;
                        Canvas.SetLeft(r, c.X);
                        Canvas.SetTop(r, c.Y);
                        if (c.ShowColor != default(Color))
                            r.Fill = new SolidColorBrush(Color.FromArgb(255, 173, 216, 230));
                        else
                            r.Fill = new SolidColorBrush(Color.FromArgb(255, 255, 255, 255));

                        Canvas.SetZIndex(r, 0);
                        panel.Children.Add(r);
                    }
                });
            }
            else
            {
                var rectList = this.panel.Children.Where(p => p is System.Windows.Shapes.Rectangle && ((System.Windows.Shapes.Rectangle)p).Tag != null).ToList();
                foreach (System.Windows.Shapes.Rectangle r in rectList)
                {
                    Cell c = r.Tag as Cell;
                    r.Width = c.Width > 0 ? c.Width - 1 : 0;
                    r.Height = c.Height > 0 ? c.Height - 1 : 0;
                    Canvas.SetLeft(r, c.X);
                    Canvas.SetTop(r, c.Y);

                    if (c.ShowColor != default(Color))
                        r.Fill = new SolidColorBrush(Color.FromArgb(255, 173, 216, 230));
                    else
                        r.Fill = new SolidColorBrush(Color.FromArgb(255, 255, 255, 255));
                }
            }

            #endregion

            #region 选择单元格时画的框
            if (selectrow == -1 && selectcolumn == -1)
            {
                if (mouse_sx != -1 && mouse_sy != -1 && mouse_ex != -1 && mouse_ey != -1)
                {
                    Rectangle rect = GetRectang();

                    System.Windows.Shapes.Rectangle r = new System.Windows.Shapes.Rectangle();
                    r.Width = rect.Width;
                    r.Height = rect.Height;
                    r.Stroke = new SolidColorBrush(Color.FromArgb(50, 25, 25, 255));
                    r.StrokeThickness = 2;
                    Canvas.SetLeft(r, rect.X);
                    Canvas.SetTop(r, rect.Y);

                    Canvas.SetZIndex(r, 0);
                    panel.Children.Add(r);
                }
            }
            #endregion

            #region 移动表格中的控件，画的对齐线
            if (ctrlmoving_x > -1 && ctrlmoving_y > -1)
            {
                Line linev = new Line();
                linev.X1 = ctrlmoving_x;
                linev.Y1 = 0;
                linev.X2 = ctrlmoving_x;
                linev.Y2 = panel.ActualHeight;
                linev.Stroke = new SolidColorBrush(Color.FromArgb(255, 255, 0, 0));
                linev.StrokeThickness = 0.5;
                panel.Children.Add(linev);

                Line lineh = new Line();
                lineh.X1 = 0;
                lineh.Y1 = ctrlmoving_y;
                lineh.X2 = panel.ActualWidth;
                lineh.Y2 = ctrlmoving_y;
                lineh.Stroke = new SolidColorBrush(Color.FromArgb(255, 255, 0, 0));
                lineh.StrokeThickness = 0.5;
                panel.Children.Add(lineh);
            }
            #endregion

            #region 移动表格的行线或列线，画的虚线
            if (selectrow != -1 || selectcolumn != -1) //拖动行或列的线条，设置宽度或高度
            {
                //Line line = new Line();
                //if (selectrow != -1)
                //    line = new Line() { X1 = PaddingLeft, Y1 = mouse_ey, X2 = PaddingLeft + TableWidth, Y2 = mouse_ey };
                //else
                //    line = new Line() { X1 = mouse_ex, Y1 = PaddingTop, X2 = mouse_ex, Y2 = PaddingTop + TableHeight };

                //line.Stroke = new SolidColorBrush(Color.FromArgb(255, 255, 0, 0));
                //line.StrokeThickness = 0.5;
                //panel.Children.Add(line);
            }
            #endregion

        }
        #endregion

        int ctrlmoving_x = -1;  //控件对齐x线
        int ctrlmoving_y = -1;  //控件对齐y线

        public void DrawCtrlMovingLine(int x, int y)
        {
            ctrlmoving_x = x - 1;
            ctrlmoving_y = y - 1;

            this.Refresh(false);
        }

        #region 选择单元格时鼠标的起始位置和结束位置
        private Rectangle GetRectang()
        {
            int tempxs = -1;
            int tempwidth = -1;
            if (mouse_sx > mouse_ex)
                tempxs = mouse_ex;
            else
                tempxs = mouse_sx;
            tempwidth = Math.Abs(mouse_sx - mouse_ex);

            int tempys = -1;
            int tempheigh = -1;
            if (mouse_sy > mouse_ey)
                tempys = mouse_ey;
            else
                tempys = mouse_sy;
            tempheigh = Math.Abs(mouse_sy - mouse_ey);

            Rectangle rect = new Rectangle(tempxs, tempys, tempwidth, tempheigh);
            return rect;
        }


        private int mouse_sx = -1;
        private int mouse_sy = -1;

        private int mouse_ex = -1;
        private int mouse_ey = -1;
        #endregion

        /// <summary>
        /// 拖动设置单元格高度或宽度时，启动后台线程更新控件的位置
        /// </summary>
        System.Windows.Threading.DispatcherTimer dtimer = null;

        #region 鼠标按下移动、弹起事件
        void Table_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            int x = mouse_sx = (int)e.GetPosition(panel).X;
            int y = mouse_sy = (int)e.GetPosition(panel).Y;

            if (_dataModel == null)
                return;

            if (true)   //e.Button == MouseButtons.Left
            {
                var tuple = GetRowColumnIndex(x, y);
                int row = tuple.Item1;
                int column = tuple.Item2;

                if (row > 0)
                    selectrow = row;
                else if (column > 0)
                    selectcolumn = column;

                Console.WriteLine("MouseDown : row={0}, column={1},  x={2}, y={3}", selectrow, selectcolumn, x, y);
                if (selectrow != -1 || selectcolumn != -1) //拖动行或列的线条，设置宽度或高度
                {
                    //关联控件和单元格
                    SetControlInCell();
                    //更新控件位置
                    if (dtimer == null)
                    {
                        dtimer = new System.Windows.Threading.DispatcherTimer()
                        {
                            Interval = TimeSpan.FromMilliseconds(50),
                        };
                        dtimer.Tick += new EventHandler((s, ee) => SetControlMoveCell());
                        dtimer.Start();
                    }
                    else
                        dtimer.Start();

                }
                else //下面是选中表格中的单元格
                {
                    for (int i = 0; i < _dataModel.Rows.Count; i++)
                    {
                        for (int j = 0; j < _dataModel.Columns.Count; j++)
                        {
                            Cell c = _dataModel.Rows[i][j] as Cell;
                            if (c.X + SELECT_SPACE < x && (c.X + c.Width - SELECT_SPACE) > x &&
                                c.Y + SELECT_SPACE < y && (c.Y + c.Height - SELECT_SPACE > y))
                            {
                                c.isSelected = true;
                            }
                            else
                                c.isSelected = false;
                        }
                    }
                    this.Refresh();
                }
            }
        }

        private int selectrow = -1;     //按下鼠标左键时选中的行线
        private int selectcolumn = -1;  //按下鼠标左键时选中的列线

        private void Table_MouseMove(object sender, MouseEventArgs e)
        {
            if (_dataModel == null) //没有初始化 数据模型
                return;

            int x = (int)e.GetPosition(panel).X;
            int y = (int)e.GetPosition(panel).Y;

            mouse_ex = x;
            mouse_ey = y;

            if (selectrow != -1 || selectcolumn != -1)  //拖动行或列的线条，设置宽度或高度
            {
                if (selectrow != -1)
                {
                    if (mouse_sy > mouse_ey)
                    {
                        var movesize = Model.ListCellHeight[selectrow - 1] - Math.Abs(mouse_sy - mouse_ey);
                        var currentRowHeight = Model.ListCellHeight.Where((p, index) => index <= selectrow - 1).Sum();
                        //间隔大于3倍空距，并且行高大于Y值最大的一个控件，则可以移动
                        if (movesize > 3 * SELECT_SPACE && currentRowHeight > GetControlMaxXY(selectrow, 0))
                            Model.ListCellHeight[selectrow - 1] = movesize;
                    }
                    else
                    {
                        var currentRowHeight = Model.ListCellHeight.Where((p, index) => index <= selectrow - 1).Sum();
                        if (mouse_sy >= currentRowHeight + SELECT_SPACE)   //鼠标右移时必须大于整体高度时才移动
                            Model.ListCellHeight[selectrow - 1] = Model.ListCellHeight[selectrow - 1] + Math.Abs(mouse_sy - mouse_ey);
                    }
                }
                else
                {
                    if (mouse_sx > mouse_ex)
                    {
                        var movesize = Model.ListCellWidth[selectcolumn - 1] - Math.Abs(mouse_sx - mouse_ex);
                        var currentColumnWidth = Model.ListCellWidth.Where((p, index) => index <= selectcolumn - 1).Sum();

                        if (movesize > 3 * SELECT_SPACE && currentColumnWidth > GetControlMaxXY(selectcolumn, 1))
                            Model.ListCellWidth[selectcolumn - 1] = movesize;
                    }
                    else
                    {
                        var currentColumnWidth = Model.ListCellWidth.Where((p, index) => index <= selectcolumn - 1).Sum();
                        if (mouse_sx >= currentColumnWidth + SELECT_SPACE)  //鼠标右移时必须大于整体宽度时才移动
                            Model.ListCellWidth[selectcolumn - 1] = Model.ListCellWidth[selectcolumn - 1] + Math.Abs(mouse_sx - mouse_ex);
                    }
                }

                //在移动事件里面直接移动控件，性能消耗太大
                //SetControlMovedCell();

                this.RefreshModel(false);
                this.Refresh(false);

                mouse_sx = mouse_ex;
                mouse_sy = mouse_ey;

                return;
            }

            #region 画选中单元格的框
            Rectangle rect = GetRectang();
            if (mouse_sx != -1 && mouse_sy != -1)   //没有按下鼠标左键
            {
                Rectangle rect1 = GetRectang();
                DataTable dtModel = this.Model;

                dtModel.AllCell.ForEach(c =>
                {
                    c.isSelected = false;
                    if (rect1.IntersectsWith(new Rectangle(c.X, c.Y, c.Width, c.Height)))
                        c.isSelected = true;
                });

                var list = dtModel.AllCell.Where(p => p.isSelected && p.isShow).ToList();
                if (list.Count() > 0)
                {
                    int sx = list.Select(p => p.X).Min();
                    int ex = list.Select(p => p.X + p.Width).Max();
                    int sy = list.Select(p => p.Y).Min();
                    int ey = list.Select(p => p.Y + p.Height).Max();
                    Rectangle rc = new Rectangle(sx, sy, ex - sx, ey - sy);

                    dtModel.AllCell.ForEach(c =>
                    {
                        if (rc.IntersectsWith(new Rectangle(c.X, c.Y, c.Width, c.Height)))
                            c.isSelected = true;
                    });
                }

                this.Refresh(false);
                return;
            }
            #endregion

            var tuple = GetRowColumnIndex(x, y);
            int row = tuple.Item1;
            int column = tuple.Item2;

            if (row > 0) this.Cursor = Cursors.SizeNS;
            else if (column > 0) this.Cursor = Cursors.SizeWE;
            else this.Cursor = Cursors.Arrow;

        }

        #region 选中调整的行线或列线
        private Tuple<int, int> GetRowColumnIndex(int x, int y)
        {
            if (PaddingLeft < x && PaddingLeft + TableWidth > x &&
                PaddingTop < y && PaddingTop + TableHeight > y)
            {
                int row = 0;
                var templist = Model.ListCellHeight.Select((p, index) => Model.ListCellHeight.Take(index + 1).Sum()).ToList();
                for (int n = 0; n < templist.Count; n++)
                    if (Math.Abs(templist[n] + PaddingTop - y) <= SELECT_SPACE) row = n + 1;

                int column = 0;
                templist = Model.ListCellWidth.Select((p, index) => Model.ListCellWidth.Take(index + 1).Sum()).ToList();
                for (int n = 0; n < templist.Count; n++)
                    if (Math.Abs(templist[n] + PaddingLeft - x) <= SELECT_SPACE) column = n + 1;

                Tuple<int, int> tuple = new Tuple<int, int>(row, column);
                return tuple;
            }
            else
                return new Tuple<int, int>(0, 0);
        }
        #endregion

        void Table_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (selectrow != -1 || selectcolumn != -1) //拖动行或列的线条，设置宽度或高度
            {
                //停止移动控件
                dtimer.Stop();
            }

            mouse_sx = -1;
            mouse_sy = -1;
            mouse_ex = -1;
            mouse_ey = -1;

            selectrow = -1;     //按下鼠标左键时选中的行线
            selectcolumn = -1;  //按下鼠标左键时选中的列线

            SetControlMoveCell();

            this.RefreshModel();
            this.Refresh();
        }

        #endregion

        #region 设置单元格大小或者合并单元格时，同时移动单元格里面的控件

        /// <summary>
        /// 获取某一行或某一列里控件的最大坐标，
        /// 避免移动单元格高度或宽度时控件越界
        /// </summary>
        /// <param name="index">行或列的索引</param>
        /// <param name="type">0 表示行， 1 表示列</param>
        /// <returns></returns>
        private int GetControlMaxXY(int index, int type)
        {
            if (type == 0)
            {
                var temp = Model.Rows[index - 1].Where(p => p.isShow && p.Contrls.Count > 0).Select(p => string.Join(",", p.Contrls.Keys.ToList())).ToList();
                var ids = string.Join(",", temp);
                var tempCtrl = panel.Children.Where(p => p is Control && (ids.IndexOf(((Control)p).Name) > -1)).Select(p => (Control)p).ToList();

                if (tempCtrl.Count > 0)
                    return (int)tempCtrl.Max(p => Canvas.GetTop(p) + p.ActualHeight);
                else
                    return 0;
            }
            else
            {
                List<Cell> columns = new List<Cell>();
                Model.Rows.ForEach(p => columns.Add(p[index - 1]));

                var temp = columns.Where(p => p.isShow && p.Contrls.Count > 0).Select(p => string.Join(",", p.Contrls.Keys.ToList())).ToList();
                var ids = string.Join(",", temp);
                var tempCtrl = panel.Children.Where(p => p is Control && (ids.IndexOf(((Control)p).Name) > -1)).Select(p => (Control)p).ToList();

                if (tempCtrl.Count > 0)
                    return (int)tempCtrl.Max(p => Canvas.GetLeft(p) + p.ActualWidth);
                else
                    return 0;
            }

        }

        /// <summary>
        /// 单元格大小改变时、移动单元格的高度和宽度时，
        /// 移动控件的位置
        /// </summary>
        private void SetControlMoveCell()
        {
            Model.AllCell.Where(p => p.isShow && p.Contrls.Count > 0).ToList().ForEach(c =>
            {
                foreach (var ctrl in c.Contrls)
                {
                    var control = (Control)panel.Children.Where(p => p is Control && ((Control)p).Name == ctrl.Key).SingleOrDefault();
                    if (control != null)
                    {
                        dynamic d = control.Tag;
                        d.LocationX = (int)ctrl.Value.X + c.X;
                        d.LocationY = (int)ctrl.Value.Y + c.Y;
                    }
                }
            });
        }

        /// <summary>
        /// 添加控件、鼠标移动控件左键弹起事件和合并单元格时，
        /// 设置单元格中包含的控件
        /// </summary>
        private void SetControlInCell()
        {
            Model.AllCell.ForEach(c =>
            {
                c.Contrls.Clear();
                if (c.isShow)
                {
                    List<Control> ctrls = GetCtrls(c);
                    foreach (Control control in ctrls)
                        c.Contrls.Add(control.Name, new Point(Canvas.GetLeft(control) - c.X, Canvas.GetTop(control) - c.Y));
                }
            });
        }
        #endregion

        #region 拖动设计控件事件
        public void AddHtmlControl(Control ctrl, Point Location = default(Point))
        {
            ctrl.Name = Guid.NewGuid().ToString();
            Canvas.SetZIndex(ctrl, 10);
            if (ctrl is CheckBox || ctrl is RadioButton || ctrl is Label)
            {
                ctrl.AddHandler(CheckBox.MouseLeftButtonDownEvent, new MouseButtonEventHandler(this.ctrl_MouseLeftButtonDown), true);
                ctrl.AddHandler(CheckBox.MouseLeftButtonUpEvent, new MouseButtonEventHandler(this.ctrl_MouseLeftButtonUp), true);
            }
            else
            {
                ctrl.MouseLeftButtonDown += ctrl_MouseLeftButtonDown;
                ctrl.MouseLeftButtonUp += ctrl_MouseLeftButtonUp;
            }
            ctrl.MouseMove += ctrl_MouseMove;

            int x = (int)this.panel.ActualWidth / 2;
            int y = (int)this.panel.ActualHeight / 2;
            List<string> l = new List<string>();

            List<Control> ctrls = this.panel.Children.Where(p => p is Control).Select(p => (Control)p).Where(p => p.Tag is HtmlLabelModel ||
             p.Tag is HtmlTextBoxModel || p.Tag is HtmlCheckBoxModel || p.Tag is HtmlRadioButtonModel).ToList();
            while (true)
            {
                //如果该位置已经存在控件，则把新控件的坐标 +15
                if (ctrls.Where(p => (int)Canvas.GetLeft(p) == x && (int)Canvas.GetTop(p) == y).FirstOrDefault() != null)
                {
                    x += 15; y += 15;
                }
                else
                    break;
            }
            if (Location == default(Point))
            {
                Canvas.SetLeft(ctrl, x);
                Canvas.SetTop(ctrl, y);
            }
            else
            {
                Canvas.SetLeft(ctrl, Location.X);
                Canvas.SetTop(ctrl, Location.Y);
            }

            this.panel.Children.Add(ctrl);

            if (CtrlSelectedEvent != null)
                CtrlSelectedEvent(ctrl, new EventArgs());

            SetControlInCell();
        }

        bool isMouseCaptured;
        double mouseVerticalPosition;
        double mouseHorizontalPosition;
        //控件是否移动过，如果有移动，则加入回滚Stack
        bool ctrlisMoved = false;
        void ctrl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (dtimer != null)
                dtimer.Stop();

            Control ctrl = sender as Control;
            mouseVerticalPosition = e.GetPosition(panel).Y;
            mouseHorizontalPosition = e.GetPosition(panel).X;
            isMouseCaptured = true;
            ctrl.CaptureMouse();

            e.Handled = true;
            DrawCtrlMovingLine((int)Canvas.GetLeft(ctrl), (int)Canvas.GetTop(ctrl));

            if (CtrlSelectedEvent != null)
            {
                CtrlSelectedEvent(sender, new EventArgs());
            }
        }

        void ctrl_MouseMove(object sender, MouseEventArgs e)
        {
            Control ctrl = sender as Control;
            if (isMouseCaptured)
            {
                ctrlisMoved = true;

                double deltaV = e.GetPosition(panel).Y - mouseVerticalPosition;
                double deltaH = e.GetPosition(panel).X - mouseHorizontalPosition;
                double newTop = deltaV + (double)ctrl.GetValue(Canvas.TopProperty);
                double newLeft = deltaH + (double)ctrl.GetValue(Canvas.LeftProperty);

                ctrl.SetValue(Canvas.TopProperty, newTop);
                ctrl.SetValue(Canvas.LeftProperty, newLeft);

                mouseVerticalPosition = e.GetPosition(panel).Y;
                mouseHorizontalPosition = e.GetPosition(panel).X;

                if (CtrlSelectedEvent != null)
                    CtrlSelectedEvent(sender, new EventArgs());
            }
            if (isMouseCaptured) DrawCtrlMovingLine((int)Canvas.GetLeft(ctrl), (int)Canvas.GetTop(ctrl));
        }

        void ctrl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            Control ctrl = sender as Control;
            isMouseCaptured = false;
            ctrl.ReleaseMouseCapture();
            mouseVerticalPosition = -1;
            mouseHorizontalPosition = -1;

            e.Handled = true;
            DrawCtrlMovingLine(-1, -1);

            //if (ctrlisMoved)
            //{
            //    ctrlisMoved = false;
            //    RefreshModel();
            //}

            SetControlInCell();
        }

        #endregion

        #region 撤销到上一次改动
        /// <summary>
        /// 回滚到最近一次改动
        /// </summary>
        public void Reversion()
        {
            if (ModelRecord.Count <= 1)
                return;

            ModelRecord.Pop();
            Model = ModelRecord.Peek().DeepCopy();

            this.RefreshModel(false);
            this.Refresh();

            //暂时不做控件回放
            //SetControlMoveCell();
        }

        #endregion

        #region 输出Html代码

        public string OutHtml()
        {
            DataTable dtModel = this.Model;
            if (dtModel == null)
                return "";

            StringBuilder stable = new StringBuilder();
            string nl = Environment.NewLine;
            stable.AppendFormat("<b><span>{0}</span></b>{1}", oa_tableTitle, nl);
            stable.AppendFormat("<input type=\"hidden\" id=\"group\" value=\"\">{0}", nl);

            stable.AppendFormat("<table cellspacing=\"1\" cellpadding=\"1\" bordercolor=\"#000000\" border=\"1\">{0}<tbody>{0}", nl);
            for (int i = 0; i < dtModel.Rows.Count; i++)
            {
                stable.AppendFormat("<tr>{0}", nl);
                for (int j = 0; j < dtModel.Columns.Count; j++)
                {
                    Cell c = dtModel.Rows[i][j];
                    if (c.isShow)
                    {
                        List<Control> ctrls = GetCtrls(c);
                        stable.Append("<td");
                        if (c.ColumnSpan != 0)
                            stable.AppendFormat(" colspan=\"{0}\"", c.ColumnSpan + 1);
                        if (c.RowSpan != 0)
                            stable.AppendFormat(" rowspan=\"{0}\"", c.RowSpan + 1);

                        if (ctrls.Count == 1 && ctrls[0].Tag is HtmlLabelModel)
                        {
                            var labModel = ctrls[0].Tag as HtmlLabelModel;
                            if (labModel.Width != 0)
                                stable.AppendFormat(" style=\"width:{0}px;\"", labModel.Width);

                            if (labModel.AType == LabelType.表单项)
                                stable.AppendFormat(" id=\"title\"");
                            else
                                stable.AppendFormat(" align=\"left\"");

                            stable.Append(">");
                            if (labModel.AType == LabelType.表单项)
                                stable.Append((labModel.Text == null ? "文本" : labModel.Text.Trim().Replace("\r", "")));
                            else
                                stable.Append((labModel.Text == null ? "文本" : labModel.Text.Trim().Replace("\r", "<br/>")));
                        }
                        else
                        {
                            //var stemp = "";
                            //if (c.Width != Cell.CellWidth)
                            //    stemp = string.Format(" width:{0}px; ", c.Width);
                            //暂时不设置高度，不然浏览器样式会乱
                            //if (c.Height != Cell.CellHeight)
                            //    stemp += string.Format(" height:{0}px; ", c.Height);
                            stable.AppendFormat(" align=\"left\"");
                            stable.Append(">");
                            stable.AppendFormat(ControlToHtml(ctrls));
                        }
                        stable.AppendFormat("</td>{0}", nl);
                    }
                }
                stable.AppendFormat("</tr>{0}", nl);
            }
            stable.AppendFormat("</tbody>{0}</table>", nl);

            var s = stable.ToString();
            return s;
        }

        /// <summary>
        /// 获得单个单元格里面的控件
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        private List<Control> GetCtrls(Cell c)
        {
            List<Control> ctrls = this.panel.Children.Where(p => p is Control).Select(p => (Control)p).Where(p => p.Tag is HtmlLabelModel ||
                p.Tag is HtmlTextBoxModel || p.Tag is HtmlCheckBoxModel || p.Tag is HtmlRadioButtonModel).
            Where(p => c.X < (int)Canvas.GetLeft(p) && (c.X + c.Width) > (int)Canvas.GetLeft(p) &&
            c.Y < (int)Canvas.GetTop(p) && (c.Y + c.Height > (int)Canvas.GetTop(p))).OrderBy(p => Canvas.GetLeft(p)).ToList();

            return ctrls;
        }

        /// <summary>
        /// 转换控件成html代码
        /// </summary>
        /// <param name="ctrl"></param>
        /// <returns></returns>
        private string ControlToHtml(List<Control> ctrls)
        {
            StringBuilder result = new StringBuilder();

            foreach (Control control in ctrls)
            {
                if (control.Tag is HtmlLabelModel)
                {
                    var ctrlModel = control.Tag as HtmlLabelModel;
                    if (ctrlModel.AType == LabelType.表单项)
                    {
                        result.AppendFormat("<label align=\"{0}\">{1}</label>",
                             ctrlModel.Align, (ctrlModel.Text == null ? "文本" : ctrlModel.Text.Trim()).Replace("\r", ""));
                    }
                    else
                    {
                        result.AppendFormat("<label align=\"{0}\">{1}</label>",
                             ctrlModel.Align, (ctrlModel.Text == null ? "文本" : ctrlModel.Text.Trim()).Replace("\r", "<br/>"));
                    }
                }
                else if (control.Tag is HtmlTextBoxModel)
                {
                    var ctrlModel = control.Tag as HtmlTextBoxModel;
                    ctrlModel.TextId = ctrlModel.TextId.Replace("\r", "");
                    if (ctrlModel.FormatType.ToString() == "部门列表")
                    {
                        result.AppendFormat("<input type=\"text\"");
                        result.AppendFormat(" name=\"{0}\" class=\"{0}\" onclick=\"OpenTitle(this,1,'80%','20%','选择部门')\" readonly=\"readonly\"", ctrlModel.TextId.Trim());
                        if (ctrlModel.Width != 90)
                            result.AppendFormat(" style=\"width:{0}px;\"", ctrlModel.Width);
                        result.Append(" />");
                    }
                    else
                    {
                        if (ctrlModel.Height > 35) //高度大于35，则认为该文本框是一个文本域
                        {
                            result.AppendFormat("<textarea ");
                            result.AppendFormat(" name=\"{0}\" class=\"{1}\"", ctrlModel.TextId.Trim(), ctrlModel.TextId.Trim() + (ctrlModel.FormatType.ToString() == "文本" ? "" : " " + ctrlModel.FormatType.ToString()));
                            result.AppendFormat(" style=\"width:99%;height:{0}px\"", ctrlModel.Height);
                            result.Append("></textarea>"); //ie必须这种方式结束
                        }
                        else
                        {
                            result.AppendFormat("<input type=\"text\"");
                            result.AppendFormat(" name=\"{0}\" class=\"{1}{2}\"", ctrlModel.TextId.Trim(), ctrlModel.TextId.Trim() + (ctrlModel.FormatType.ToString() == "文本" ? "" : " " + ctrlModel.FormatType.ToString()), ctrlModel.DefaultEntry.ToString() == "请选择" ? "" : " " + ctrlModel.DefaultEntry.ToString());
                            if (ctrlModel.Width != 90)
                                result.AppendFormat(" style=\"width:{0}px;\"", ctrlModel.Width);
                            result.Append(" />");
                        }
                    }
                }
                else if (control.Tag is HtmlCheckBoxModel)
                {
                    var ctrlModel = control.Tag as HtmlCheckBoxModel;
                    ctrlModel.TextId = ctrlModel.TextId.Replace("\r", "");
                    result.AppendFormat("<input name=\"{0}\" class=\"{0}\"{1} value=\"{2}\" /><label>{2}</label>",
                        ctrlModel.TextId, ctrlModel.ExtProperty(), ctrlModel.Text);
                }
                else if (control.Tag is HtmlRadioButtonModel)
                {
                    var ctrlModel = control.Tag as HtmlRadioButtonModel;
                    ctrlModel.TextId = ctrlModel.TextId.Replace("\r", "");
                    result.AppendFormat("<input name=\"{0}\" class=\"{0}\"{1} value=\"{2}\" /><label>{2}</label>",
                        ctrlModel.TextId, ctrlModel.ExtProperty(), ctrlModel.Text);
                }
            }
            var s = result.ToString();
            if (s == "") s = "&nbsp;";
            return s;
        }
        #endregion

        #region 序列化和反序列化
        public string TableSerializ()
        {
            TableSerialization ts = new TableSerialization();
            ts.Model = _dataModel.DeepCopy();

            List<Control> listCtrl = this.panel.Children.Where(p => p is Control).Select(p => (Control)p).Where(p => p.Tag is HtmlLabelModel || p.Tag is HtmlTextBoxModel ||
                p.Tag is HtmlCheckBoxModel || p.Tag is HtmlRadioButtonModel).ToList();

            ts.ListLab = listCtrl.Where(p => p.Tag.GetType().Name == "HtmlLabelModel").Select(p => (HtmlLabelModel)p.Tag).ToList();
            ts.ListTxtbox = listCtrl.Where(p => p.Tag.GetType().Name == "HtmlTextBoxModel").Select(p => (HtmlTextBoxModel)p.Tag).ToList();
            ts.ListChkbox = listCtrl.Where(p => p.Tag.GetType().Name == "HtmlCheckBoxModel").Select(p => (HtmlCheckBoxModel)p.Tag).ToList();
            ts.ListRadbtn = listCtrl.Where(p => p.Tag.GetType().Name == "HtmlRadioButtonModel").Select(p => (HtmlRadioButtonModel)p.Tag).ToList();

            byte[] json = null;
            DataContractSerializer ser = new DataContractSerializer(typeof(TableSerialization));
            using (MemoryStream ms = new MemoryStream())
            {
                ser.WriteObject(ms, ts);
                json = ms.ToArray();
            }
            string jsonString = Encoding.UTF8.GetString(json, 0, json.Length);//序列化得到的字符串 
            return jsonString;
        }

        public void TableUnSerializ(string jsonString)
        {
            this.panel.Children.Clear();
            TableSerialization ts = new TableSerialization();
            DataContractSerializer ser = new DataContractSerializer(typeof(TableSerialization));
            using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonString)))
            {
                ts = (TableSerialization)ser.ReadObject(ms);
            }
            _dataModel = ts.Model;

            foreach (var lab in ts.ListLab)
            {

                Label ctrl = new Label();
                ctrl.Tag = lab;

                Canvas.SetLeft(ctrl, lab.LocationX);
                Canvas.SetTop(ctrl, lab.LocationY);
                lab.ctrl = ctrl;
                ctrl.Content = lab.Text;

                this.AddHtmlControl(ctrl, new Point(lab.LocationX, lab.LocationY));
            }

            foreach (var txtbox in ts.ListTxtbox)
            {
                Label ctrl = new Label();
                ctrl.Content = "";
                ctrl.Width = 90;
                ctrl.Height = 20;
                ctrl.BorderThickness = new Thickness(1);
                ctrl.Background = new SolidColorBrush(Color.FromArgb(255, 255, 255, 255));
                ctrl.BorderBrush = new SolidColorBrush(Color.FromArgb(255, 0, 0, 0));

                ctrl.Tag = txtbox;
                Canvas.SetLeft(ctrl, txtbox.LocationX);
                Canvas.SetTop(ctrl, txtbox.LocationY);
                txtbox.ctrl = ctrl;
                ctrl.Width = txtbox.Width;
                ctrl.Height = txtbox.Height;

                this.AddHtmlControl(ctrl, new Point(txtbox.LocationX, txtbox.LocationY));
            }

            foreach (var chekcbox in ts.ListChkbox)
            {
                CheckBox ctrl = new CheckBox();
                ctrl.Tag = chekcbox;
                Canvas.SetLeft(ctrl, chekcbox.LocationX);
                Canvas.SetTop(ctrl, chekcbox.LocationY);
                chekcbox.ctrl = ctrl;
                ctrl.Content = chekcbox.Text;

                this.AddHtmlControl(ctrl, new Point(chekcbox.LocationX, chekcbox.LocationY));
            }

            foreach (var radio in ts.ListRadbtn)
            {
                RadioButton ctrl = new RadioButton();
                ctrl.Tag = radio;
                Canvas.SetLeft(ctrl, radio.LocationX);
                Canvas.SetTop(ctrl, radio.LocationY);
                radio.ctrl = ctrl;
                ctrl.Content = radio.Text;

                this.AddHtmlControl(ctrl, new Point(radio.LocationX, radio.LocationY));
            }

            this.RefreshModel();
            this.Refresh();
        }
        #endregion

        #region 上传或下载数据
        public void SaveTableData()
        {
            #region 验证数据
            Func<string, bool> fnValid = (Func<string, bool>)(s =>
            {
                foreach (var c in s)
                {
                    //只能通过汉字，数字，和英文字母
                    Regex rx = new Regex("^[\u4e00-\u9fa5]$");
                    if (!(rx.IsMatch(c.ToString()) || char.IsLetterOrDigit(c) || c == '\r'))
                        return false;
                }
                return true;
            });

            List<Control> ctrls = this.panel.Children.Where(p => p is Control).Select(p => (Control)p).Where(p => p.Tag is HtmlLabelModel ||
            p.Tag is HtmlTextBoxModel || p.Tag is HtmlCheckBoxModel || p.Tag is HtmlRadioButtonModel).ToList();

            int imax = ctrls.Where(p => p.Tag is HtmlLabelModel).GroupBy(p => ((dynamic)p.Tag).Text).Max(p => p.ToList().Count);
            if (imax > 1)
            {
                MessageBox.Show(string.Format("文本控件有重复！"));
                return;
            }
            foreach (var control in ctrls)
            {
                if (control.Tag is HtmlLabelModel)
                {
                    object txt = control.Tag.GetType().GetProperty("Text").GetValue(control.Tag, null);
                    object type = control.Tag.GetType().GetProperty("AType").GetValue(control.Tag, null);
                    if (txt == null || txt.ToString() == "文本")
                    {
                        MessageBox.Show(string.Format("文本控件’没有设置文本属性！"));
                        return;
                    }
                    else
                    {
                        if (Convert.ToInt32(type) != 1)
                        {
                            if (!fnValid(txt.ToString()))
                            {
                                MessageBox.Show(string.Format("文本只能输入汉字、字母和数字！"));
                                return;
                            }
                        }
                    }
                }
                else
                {
                    object txtid = control.Tag.GetType().GetProperty("TextId").GetValue(control.Tag, null);
                    if (txtid == null || txtid.ToString() == "请选择")
                    {
                        MessageBox.Show(string.Format("有控件没有设置\"关联项\"属性！"));
                        return;
                    }
                }
            }



            #endregion

            string host = Application.Current.Host.Source.Host;
            string port = Application.Current.Host.Source.Port.ToString();
            string url = string.Format("http://{0}:{1}/Form/EditReturn", host, port);

            try
            {
                if (HtmlPage.Document.QueryString != null && HtmlPage.Document.QueryString.ContainsKey("id"))
                    int.TryParse(HtmlPage.Document.QueryString["id"], out oa_tableID);

            }
            catch (Exception err)
            {
                MessageBox.Show("请在web环境下运行！" + err.Message);
                return;
            }
            if (oa_tableID <= 0)
            {
                MessageBox.Show("编号错误！"); return;
            }

            UriBuilder ub = new UriBuilder(url);
            WebClient wc = new WebClient();
            wc.UploadStringCompleted += (sender, e) =>
            {
                string sresult = "";
                try
                {
                    sresult = e.Result;
                    MessageBox.Show(sresult);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("错误：" + ex.Message); return;
                }
            };

            string html = this.OutHtml(); 
            string serializData = TableSerializ();
            html = HttpUtility.UrlEncode(html);
            serializData = HttpUtility.UrlEncode(serializData);
            wc.Headers["Content-Type"] = "application/x-www-form-urlencoded";
            wc.UploadStringAsync(ub.Uri, "post", string.Format("fid={0}&fbody={1}&fnote={2}", oa_tableID, html, serializData));
        }
        //oa传过来的表格ID
        int oa_tableID = 0;
        string oa_tableTitle = "";

        public void ReadTableData(int oa_tableID)
        {
            string host = Application.Current.Host.Source.Host;
            string port = Application.Current.Host.Source.Port.ToString();
            string url = string.Format("http://{0}:{1}/Form/Edit", host, port);
            this.oa_tableID = oa_tableID;

            UriBuilder ub = new UriBuilder(url);
            WebClient wc = new WebClient();
            wc.Headers["Content-Type"] = "application/x-www-form-urlencoded";
            wc.UploadStringAsync(ub.Uri, "post", string.Format("id={0}", oa_tableID));

            wc.UploadStringCompleted += (sender, e) =>
            {
                var sresult = "";
                try
                {
                    sresult = e.Result;
                    if (string.IsNullOrEmpty(sresult))
                        return;
                    JsonClass jc = null;
                    try
                    {
                        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(JsonClass));
                        using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(sresult.Trim())))
                        {
                            jc = (JsonClass)ser.ReadObject(ms);
                            oa_tableTitle = jc.FName;
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("错误：" + ex.Message);
                        return;
                    }
                    //反序列化表格对象
                    if (jc != null && !string.IsNullOrEmpty(jc.FNote))
                    {
                        TableUnSerializ(HttpUtility.UrlDecode(jc.FNote));
                    }
                    else
                    {
                        InitTable();
                        RefreshModel();
                        Refresh();
                        SetControlInCell();
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("错误： " + ex.Message); return;
                }
            };

        }
        #endregion

    }

}
